
Photo by Michael on iPhone
秋天時期,冰川融化差不多了🧊
整理在 UIKit MVVM 架構下,頁面與頁面之間怎麼傳值,
UIKit 有這些實作招式
class CustomViewController: UIViewController, CustomViewModelDelegate {
    @IBOutlet weak var titleLabel: UILabel!
    
    var viewModel: CustomViewModel
    
    required init?(coder: NSCoder) {
        self.viewModel = CustomViewModel()
        super.init(coder: coder)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.viewModel.delegate = self
    }
    
    func updateTitle(title: String) {
        self.titleLabel.text = title
    }
}
protocol CustomViewModelDelegate: AnyObject {
    func updateTitle(title: String)
}
class CustomViewModel {
    weak var delegate: CustomViewModelDelegate?
}
// MARK: - Interface Methods
extension CustomViewModel {
    func updateTitleAction(title: String) {
        delegate?.updateTitle(title: title)
    }
}
extension Notification.Name {
    enum settings {
        static let domainExpansion = NSNotification.Name("domainExpansion")
        static let 黑閃 = NSNotification.Name("黑閃")
    }
}
struct SettingsView: View {
    @State private var domainExpansion: String = "No Domain Expansion Yet"
    var body: some View {
        VStack {
            Text(domainExpansion)
                .onReceive(NotificationCenter.default.publisher(for: .settings.domainExpansion)) { (output) in
                     if let newDomainExpansion = output.object as? String {
                         self.domainExpansion = newDomainExpansion
                     }
                }
        }
    }
}
Other 頁面
Button(action: {
    NotificationCenter.default.post(name: .settings.domainExpansion, object: "簡易領域")
}) {
    Text("🫸🏻🫷🏻")
}
Tips :
在 SwiftUI 中,你沒有像 UIKit 中的 viewDidLoad、viewWillAppear 或 deinit 這樣的生命週期方法。所以,你不能像在 UIKit 中那樣在 deinit 中調用 NotificationCenter.default.removeObserver(self)。
不過,當使用 NotificationCenter 的 publisher(for:name:object:) 方法與 SwiftUI 的 onReceive 結合時,你實際上不需要手動移除觀察者。當 View 被釋放或消失時,系統會自動處理這些訂閱和取消訂閱。
class CustomViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        viewModel.isViewVisibleChanged = { [weak self] in
            self?.refreshActionButton()
        }
    }
    func refreshActionButton() {
        
    }
}
class CustomViewModel {
    
    var isViewVisibleChanged: (() -> Void)?
    var isViewVisible: Bool = false {
        didSet {
            isViewVisibleChanged?()
        }
    }
}
// MARK: - Private Methods
extension CustomViewModel {
    func change() {
        DispatchQueue.main.async {
            self.isViewVisible = true
        }
    }
}
Objective-C 的產物,所以不特別實作。
Key-Value Observing(KVO)是一種 Objective-C 編程模式,允許一個物件觀察另一物件的屬性的變化。它主要基於 Objective-C 的動態性質。在 Swift 中使用 KVO 有一些要求和考慮事項,但它仍然可以與 NSObject 的子類一起使用。
使用 KVO 的基本步驟是:
NSObject。@objc dynamic 修飾,以確保它們是動態的。addObserver(_:forKeyPath:options:context:) 方法註冊它要觀察的屬性。observeValue(forKeyPath:of:change:context:) 方法會被呼叫。removeObserver(_:forKeyPath:) 來停止觀察。以下是一個簡單的範例:
import Foundation
class Person: NSObject {
    @objc dynamic var name: String = ""
}
class Observer: NSObject {
    var person: Person
    var observation: NSKeyValueObservation?
    init(person: Person) {
        self.person = person
        super.init()
        observation = person.observe(\\.name, options: [.new], changeHandler: { (object, change) in
            if let newValue = change.newValue {
                print("Name changed to \\(newValue)")
            }
        })
    }
}
let person = Person()
let observer = Observer(person: person)
person.name = "John"
// 輸出: "Name changed to John"
person.name = "Jane"
// 輸出: "Name changed to Jane"
雖然 KVO 在 Objective-C 中很受歡迎,但在 Swift 中,很多人傾向於使用其他模式,例如 Delegate、Closure 或 Combine Framework,因為它們提供了更加 Swift 式的語法和功能。
下次介紹 Swift 新的傳值框架